package com.ntd.study.database;

import ntd.util.UtilJedis;
import cn.hutool.core.lang.Console;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * redis 相关信息
 * 1.缓存：合理使用缓存加快数据访问速度，降低后端数据源压力
 * 2.排行榜：按照热度排名，按照发布时间排行，主要用到列表和有序集合
 * 3.计算器应用：视频网站播放数，网站浏览数，使用redis计数
 * 4.社交网络：赞、踩、粉丝、下拉刷新
 * 5.消息队列：发布和订阅
 * <p>
 * 多路复用机制
 * <p>
 * 持久化策略 RDB AOF
 * RDB 快照
 * 1.生成快照（.rdb）保存到硬盘，持久化结束后，用这个临时文件替换上次持久化的文件，达到数据恢复。
 * 2.使用单独子进程来进行持久化。
 * 3.持久化间隔时间发生故障，会出现数据丢失
 * 4.手动触发命令 save - bgsave
 * |-- save 阻塞
 * |-- bgsave 创建子线程进行持久化，阻塞时间很短，在执行shutdown关闭redis服务时，如果没有开启AOF会自动执行该命令
 * AOF 日志
 * 1.以格式化指令的方式追加到操作日志(.aof)文件的尾部
 * 2.先写入指令到日志文件，才进行实际的数据变更
 * 3.数据恢复时直接repaly此日志文件
 * 4.开启 redis.conf - appendonly yes （默认为no）
 * 5.默认文件名 appendfilename "appendonly.aof"
 * <p>
 * 哨兵机制 redis sentinel 是一个分布式架构
 * 1.其中包含了若干个sentinel节点和Redis节点，每个sentinel节点会对数据节点和sentinel节点进行监控，当他发现节点不可达，会对节点做下线标识，如果大部分seltinel节点认为主节点不可达，sentinal节点之间会协商选举出来一个seltinal节点完成故障转移，并同时把这个故障通知到应用方。
 * <p>
 * redis 集群方案 RedisCluster 3.0版本后推出的方案，一个redis集群包含16384个哈希槽（hash slot），数据库中的每个数据都属于这16384个哈希槽中的一个，集群使用公式（CRC16[key]&16383）函数来计算键key属于哪个槽，集群中的每一个节点负责处理一部分哈希槽。
 * <p>
 * redis 没有真正意义的读写分离，本来就是基于缓存的，不是很有必要
 * <p>
 * 同步策略：全量复制，部分复制
 */
public class StudyDataBaseRedis {

    static UtilJedis utilJedis = UtilJedis.me();

    public static void main(String[] args) {
        final StudyDataBaseRedis studyDataBaseRedis = new StudyDataBaseRedis();
        studyDataBaseRedis.init();
        studyDataBaseRedis.handleHash();
    }

    private void init() {
        final Set<String> keys = utilJedis.keys("*"); // 查询所有key
        Console.log(keys);
    }

    /**
     * hash 字典操作
     * 1.键值对集合 - 键不能重复
     * 2.适合用于存储对象
     * 3.并且可以像数据库中update一个属性一样只修改某一项属性值
     */
    private void handleHash() {
        utilJedis.hmset("hash-key", new HashMap() {{
            put("key1", "val1");
            put("key2", "val2");
            put("key3", "val3");
        }});
        final Map<String, String> stringStringMap = utilJedis.hgetAll("hash-key");
        Console.log(stringStringMap);
    }

    /**
     * set 操作
     * 1.数值不可以重复 - 哈希表实现,元素不重复
     * 2.无序 - zset 有序
     * 3.添加、删除,查找的复杂度都是O(1) 2
     * 4.为集合提供了求交集、并集、差集等操作
     * 适用场景
     * 1、共同好友 2、利用唯一性,统计访问网站的所有独立ip 3、好友推荐时,根据tag求交集,大于某个阈值就可以推荐
     */
    private void handleSet() {
        utilJedis.sadd("set-key", "张三");
        utilJedis.sadd("set-key", "张三");
        utilJedis.sadd("set-key", "李四");
        final Set<String> smembers = utilJedis.smembers("set-key");
        Console.log(smembers);

        // zset 数据插入集合时,已经进行天然排序 1、排行榜 2、带权重的消息队列
        utilJedis.zadd("zset-key", 0, "张三");
        utilJedis.zadd("zset-key", 0, "李四");
        utilJedis.zadd("zset-key", 0, "王五");
        final Set<String> zrange = utilJedis.zrange("zset-key", 0, 1000);
        Console.log(zrange);
    }

    /**
     * list 操作
     * 1.数值可以重复
     * 2.有序
     * 3.链表(双向链表)
     * 4.增删快,提供了操作某一段元素的API
     * 适用场景
     * 1,最新消息排行等功能(比如朋友圈的时间线) 2,消息队列
     */
    private void handleList() {
        utilJedis.del("list-key"); // 删除某个key
        utilJedis.lpush("list-key", "val1");
        utilJedis.lpush("list-key", "val1");
        utilJedis.lpush("list-key", "val1");
        final List<String> lrange = utilJedis.lrange("list-key", 0, 10);
        Console.log(lrange);
    }

    /**
     * jedis 字符串操作
     * 1.一个键最大能存储512M
     * 2.可以包含任何数据,比如jpg图片或者序列化的对象
     */
    private void handleStr() {
        // 普通存值 字符串
        utilJedis.set("key", "123");
        // 普通取值 字符串
        final String key = utilJedis.get("key");
        Console.log(key);
    }

}
